/**
 * @file protocol_types.h
 * @brief 104协议基础类型定义
 * @author 电网104协议开发团队
 * @date 2024
 */

#ifndef PROTOCOL_TYPES_H
#define PROTOCOL_TYPES_H

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif

/* ==================== 基础数据类型定义 ==================== */

typedef uint8_t     u8;
typedef uint16_t    u16;
typedef uint32_t    u32;
typedef uint64_t    u64;
typedef int8_t      s8;
typedef int16_t     s16;
typedef int32_t     s32;
typedef int64_t     s64;

/* ==================== 104协议常量定义 ==================== */

/* 公共地址 - 根据IEC 60870-5-104协议标准规定 */
#define PROTOCOL_104_COMMON_ADDRESS    1    /* 主站公共地址，协议标准规定 */

/* 协议控制机制 - 根据IEC 60870-5-104协议标准规定 */
#define PROTOCOL_104_AUTO_STARTDT      true    /* 自动启动数据传输，协议标准规定 */
#define PROTOCOL_104_AUTO_TESTFR       true    /* 自动发送测试帧，协议标准规定 */
#define PROTOCOL_104_TESTFR_INTERVAL   20      /* 测试帧发送间隔(秒)，协议标准规定 */
#define PROTOCOL_104_MAX_RETRY_COUNT   3       /* 最大重试次数，协议标准规定 */
#define PROTOCOL_104_TIMEOUT_MS        3000    /* 协议超时时间(毫秒)，协议标准规定 */

/* 协议相关数据类型 */
typedef u16         seq_num_t;          /* 序列号类型 */
typedef u16         addr_t;             /* 地址类型 */
typedef u32         info_addr_t;        /* 信息对象地址类型 */

/* ==================== 协议常量定义 ==================== */

/* APDU 基本常量 */
#define APDU_START_CHAR        0x68    /* 启动字符 */
#define APDU_MAX_LENGTH        253     /* APDU最大长度 */
#define APCI_LENGTH            4       /* APCI控制域长度 */
#define ASDU_MAX_LENGTH        249     /* ASDU最大长度 */

/* 控制域格式标志 */
#define I_FORMAT_FLAG          0x00    /* I格式标志 */
#define S_FORMAT_FLAG          0x01    /* S格式标志 */
#define U_FORMAT_FLAG          0x03    /* U格式标志 */

/* U格式控制功能 */
#define STARTDT_ACT            0x07    /* 启动数据传输激活 */
#define STARTDT_CON            0x0B    /* 启动数据传输确认 */
#define STOPDT_ACT             0x13    /* 停止数据传输激活 */
#define STOPDT_CON             0x23    /* 停止数据传输确认 */
#define TESTFR_ACT             0x43    /* 测试帧激活 */
#define TESTFR_CON             0x83    /* 测试帧确认 */

/* ==================== APDU相关定义 ==================== */
#define APDU_START_CHAR        0x68    /* APDU启动字符 */
#define APDU_MIN_LENGTH        4       /* APDU最小长度 */
#define APDU_MAX_LENGTH        253     /* APDU最大长度 */

/* APDU控制域结构 */
typedef struct {
    u8 control1;                /* 控制域字节1 */
    u8 control2;                /* 控制域字节2 */
    u8 control3;                /* 控制域字节3 */
    u8 control4;                /* 控制域字节4 */
} apdu_control_field_t;

/* APDU结构 */
typedef struct {
    u8 start;                   /* 启动字符 */
    u8 length;                  /* 长度 */
    apdu_control_field_t control_field;  /* 控制域 */
    u8* asdu_data;              /* ASDU数据部分 */
    u8 checksum;                /* 校验和 */
} apdu_t;

/* U格式类型枚举 */
typedef enum {
    U_FORMAT_INVALID = 0x00,        /* 无效U格式 */
    U_FORMAT_STARTDT_ACT = 0x07,    /* 启动数据传输激活 */
    U_FORMAT_STARTDT_CON = 0x0B,    /* 启动数据传输确认 */
    U_FORMAT_STOPDT_ACT = 0x13,     /* 停止数据传输激活 */
    U_FORMAT_STOPDT_CON = 0x23,     /* 停止数据传输确认 */
    U_FORMAT_TESTFR_ACT = 0x43,     /* 测试帧激活 */
    U_FORMAT_TESTFR_CON = 0x83      /* 测试帧确认 */
} u_format_type_t;

/* 可变结构限定词 */
typedef struct {
    u8 number_of_objects : 7;   /* 信息对象个数 */
    u8 sq : 1;                  /* 结构限定词 */
} vsq_t;

/* ASDU公共地址类型 */
typedef u16 asdu_common_address_t;

/* 类型标识类型 */
typedef u8 type_id_t;

/* 传送原因类型 */
typedef u8 cause_of_transmission_t;


/* ASDU结构 */
typedef struct {
    u8 type_id;                 /* 类型标识 */
    vsq_t vsq;                  /* 可变结构限定词 */
    u8 cause_of_transmission;   /* 传送原因 */
    u16 common_address;        /* 公共地址 */
    u8* information_objects;   /* 信息对象 */
    u8* info_object_data;      /* 信息对象数据 */
    u16 information_objects_length; /* 信息对象长度 */
    u16 length;                 /* ASDU长度 */
} asdu_t;

/* 命令限定词 */
typedef struct {
    u8 qu : 5;                  /* 限定词 */
    u8 se : 1;                  /* 选择 */
    u8 ex : 1;                  /* 执行 */
    u8 reserved : 1;            /* 保留 */
} qoc_t;

/* 单点信息对象 */
typedef struct {
    u16 info_addr;              /* 信息地址 */
    u8 siq;                     /* 单点信息品质 */
} single_point_info_t;

/* 双点信息对象 */
typedef struct {
    u16 info_addr;              /* 信息地址 */
    u8 diq;                     /* 双点信息品质 */
} double_point_info_t;

/* 测量值信息对象 */
typedef struct {
    u16 info_addr;              /* 信息地址 */
    u32 value;                  /* 测量值 */
    u8 qds;                     /* 品质描述词 */
} measurement_info_t;

/* 单命令信息对象 */
typedef struct {
    u16 info_addr;              /* 信息地址 */
    u8 sco;                     /* 单命令状态 */
    u8 qos;                     /* 限定词 */
} single_command_info_t;

/* 双命令信息对象 */
typedef struct {
    u16 info_addr;              /* 信息地址 */
    u8 dco;                     /* 双命令状态 */
    u8 qos;                     /* 限定词 */
} double_command_info_t;

/* 限定词类型（与命令限定词相同） */
typedef qoc_t qoi_t;

/* ==================== 错误码定义 ==================== */
/* 错误码定义在 error_codes.h 中 */
#include "error_codes.h"

/* ==================== 品质描述词定义 ==================== */

/* SIQ (单点信息品质描述词) */
typedef struct {
    u8 spi : 1;         /* 单点信息位 (Bit 1) */
    u8 reserved : 3;    /* 保留位 (Bit 4-2) */
    u8 bl : 1;          /* 闭锁位 (Bit 5) */
    u8 sb : 1;          /* 替代位 (Bit 6) */
    u8 nt : 1;          /* 非当前值位 (Bit 7) */
    u8 iv : 1;          /* 无效位 (Bit 8) */
} siq_t;

/* DIQ (双点信息品质描述词) */
typedef struct {
    u8 dpi : 2;         /* 双点信息位 (Bit 2-1) */
    u8 reserved : 2;    /* 保留位 (Bit 4-3) */
    u8 bl : 1;          /* 闭锁位 (Bit 5) */
    u8 sb : 1;          /* 替代位 (Bit 6) */
    u8 nt : 1;          /* 非当前值位 (Bit 7) */
    u8 iv : 1;          /* 无效位 (Bit 8) */
} diq_t;

/* QDS (品质描述词) */
typedef struct {
    u8 ov : 1;          /* 溢出位 (Bit 1) */
    u8 reserved : 3;    /* 保留位 (Bit 4-2) */
    u8 bl : 1;          /* 闭锁位 (Bit 5) */
    u8 sb : 1;          /* 替代位 (Bit 6) */
    u8 nt : 1;          /* 非当前值位 (Bit 7) */
    u8 iv : 1;          /* 无效位 (Bit 8) */
} qds_t;

/* DCO (双点遥控信息元素) */
typedef struct {
    u8 dcs : 2;         /* 双点命令状态 (Bit 2-1) */
    u8 qu : 5;          /* 限定词 (Bit 7-3) */
    u8 se : 1;          /* 选择/执行 (Bit 8) */
} dco_t;

/* 单点遥控命令 */
typedef struct {
    u8 scs : 1;         /* 单点命令状态 (Bit 1) */
    u8 reserved : 1;    /* 保留位 (Bit 2) */
    u8 qu : 5;          /* 限定词 (Bit 7-3) */
    u8 se : 1;          /* 选择/执行 (Bit 8) */
} single_command_t;

/* 双点遥控命令 */
typedef struct {
    u8 dcs : 2;         /* 双点命令状态 (Bit 2-1) */
    u8 qu : 5;          /* 限定词 (Bit 7-3) */
    u8 se : 1;          /* 选择/执行 (Bit 8) */
} double_command_t;

/* ==================== 时间戳定义 ==================== */

/**
 * @brief CP56Time2a时间戳结构
 */
typedef struct {
    u16 milliseconds;   /* 毫秒 (0-59999) */
    u8 minutes;         /* 分钟 (0-59) */
    u8 hours;           /* 小时 (0-23) */
    u8 day_of_month;    /* 日 (1-31) */
    u8 month;           /* 月 (1-12) */
    u8 year;            /* 年 (0-99, 表示2000-2099) */
    u8 day_of_week;     /* 星期 (1-7, 1=星期一) */
} cp56time2a_t;

/* ==================== 信息对象定义 ==================== */

/**
 * @brief 信息对象结构
 */
typedef struct {
    info_addr_t addr;   /* 信息对象地址 */
    u8* data;          /* 信息对象数据 */
    u32 data_length;   /* 数据长度 */
} info_object_t;


/* ==================== 通用宏定义 ==================== */

/* 字节序转换宏 */
#define SWAP16(x)   ((((x) & 0xFF) << 8) | (((x) >> 8) & 0xFF))
#define SWAP32(x)   ((((x) & 0xFF) << 24) | ((((x) >> 8) & 0xFF) << 16) | \
                     ((((x) >> 16) & 0xFF) << 8) | (((x) >> 24) & 0xFF))

/* 数组大小宏 */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

/* 最小值/最大值宏 */
#define MIN(a, b)   ((a) < (b) ? (a) : (b))
#define MAX(a, b)   ((a) > (b) ? (a) : (b))

/* 位操作宏 */
#define BIT(n)      (1U << (n))
#define SET_BIT(var, bit)    ((var) |= (bit))
#define CLEAR_BIT(var, bit)  ((var) &= ~(bit))
#define TEST_BIT(var, bit)   (((var) & (bit)) != 0)

#ifdef __cplusplus
}
#endif

/* ==================== 函数声明 ==================== */

/**
 * @brief 初始化CP56Time2a时间戳
 * @details 初始化CP56Time2a时间戳结构，设置为当前时间
 * 
 * @param cp56time CP56Time2a时间戳结构指针
 * @return 协议错误码
 */
protocol_error_t init_cp56time2a(cp56time2a_t* cp56time);

/**
 * @brief 验证CP56Time2a时间戳
 * @details 验证CP56Time2a时间戳的有效性
 * 
 * @param cp56time CP56Time2a时间戳结构指针
 * @return 协议错误码
 */
protocol_error_t validate_cp56time2a(const cp56time2a_t* cp56time);

/**
 * @brief 初始化QDS品质描述词
 * @details 初始化QDS品质描述词结构
 * 
 * @param qds QDS品质描述词结构指针
 * @return 协议错误码
 */
protocol_error_t init_qds(qds_t* qds);

/**
 * @brief 验证QDS品质描述词
 * @details 验证QDS品质描述词的有效性
 * 
 * @param qds QDS品质描述词结构指针
 * @return 协议错误码
 */
protocol_error_t validate_qds(const qds_t* qds);

/**
 * @brief 验证信息对象地址
 * @details 验证信息对象地址的有效性
 * 
 * @param address 信息对象地址
 * @return 验证结果
 */
/* is_info_address_valid is declared in validation_utils.h */

/**
 * @brief 初始化APDU
 * @details 初始化APDU结构
 * 
 * @param apdu APDU结构指针
 * @return 协议错误码
 */
protocol_error_t init_apdu(apdu_t* apdu);

/**
 * @brief 验证APDU
 * @details 验证APDU结构的有效性
 * 
 * @param apdu APDU结构指针
 * @return 协议错误码
 */
protocol_error_t validate_apdu(const apdu_t* apdu);

/* ==================== APDU格式类型定义 ==================== */

/**
 * @brief APDU格式类型
 */
typedef enum {
    APDU_FORMAT_I = 0,        /* I格式APDU */
    APDU_FORMAT_S = 1,        /* S格式APDU */
    APDU_FORMAT_U = 2,        /* U格式APDU */
    APDU_FORMAT_INVALID = 3   /* 无效格式 */
} apdu_format_t;

/**
 * @brief 检测APDU格式类型
 * @details 根据控制域检测APDU的格式类型（I格式、S格式、U格式）
 *
 * @param apdu APDU结构指针
 * @return APDU格式类型
 */
apdu_format_t detect_apdu_format(const apdu_t* apdu);

/**
 * @brief 检查是否为I格式APDU
 * @details 检查APDU是否为I格式
 * 
 * @param apdu APDU结构指针
 * @return 检查结果
 */
int is_i_format_apdu(const apdu_t* apdu);

/**
 * @brief 检查是否为S格式APDU
 * @details 检查APDU是否为S格式
 * 
 * @param apdu APDU结构指针
 * @return 检查结果
 */
int is_s_format_apdu(const apdu_t* apdu);

/**
 * @brief 检查是否为U格式APDU
 * @details 检查APDU是否为U格式
 * 
 * @param apdu APDU结构指针
 * @return 检查结果
 */
int is_u_format_apdu(const apdu_t* apdu);

/**
 * @brief 初始化ASDU
 * @details 初始化ASDU结构
 * 
 * @param asdu ASDU结构指针
 * @return 协议错误码
 */
protocol_error_t init_asdu(asdu_t* asdu);

/**
 * @brief 验证ASDU
 * @details 验证ASDU结构的有效性
 * 
 * @param asdu ASDU结构指针
 * @return 协议错误码
 */
protocol_error_t validate_asdu(const asdu_t* asdu);

/**
 * @brief 验证APDU长度
 * @details 验证APDU长度是否有效
 * 
 * @param length APDU长度
 * @return 验证结果
 */
int is_apdu_length_valid(u8 length);

/**
 * @brief 验证APDU控制域
 * @details 验证APDU控制域是否有效
 * 
 * @param control_field APDU控制域
 * @return 验证结果
 */
int is_apdu_control_valid(const apdu_control_field_t* control_field);

/* parse_asdu 函数在 asdu_parser.h 中声明 */

#endif /* PROTOCOL_TYPES_H */
